﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web.UI.WebControls;
using Hematology.HmtMembership;
using Hematology.Tools;
using Hematology.Data;
using Hematology.Tools.Storage;
using Hematology.Tools.Text;
using Hematology.UserSite.Controls;
using NgoResource = Hematology.UserSite.App_GlobalResources.UserSite;

namespace Hematology.UserSite.admin
{
	public partial class UserManagement : NgoPage
	{
		#region Fields

		private const string ListUrl = "/admin/UserManagement.aspx?view=List";

		#endregion

		#region Properties

		private EnumHelper.PageSection CurrentPageSection
		{
			get
			{
				return ViewState["CurrentPageSection"] != null
						   ? (EnumHelper.PageSection)Enum.Parse(typeof(EnumHelper.PageSection), ViewState["CurrentPageSection"].ToString())
						   : EnumHelper.PageSection.List;
			}
			set { ViewState["CurrentPageSection"] = value; }
		}

		private SiteUserExtended CurrentSiteUserExtended
		{
			get { return (SiteUserExtended)ViewState["CurrentSiteUserExtended"]; }
			set { ViewState["CurrentSiteUserExtended"] = value; }
		}

		#endregion

		#region Fill methods

		private void FillLetterList()
		{
			string[] cLetterList = TextHelper.RussianAlphabet;

			rptAlphabetLinks.DataSource = cLetterList;
			rptAlphabetLinks.DataBind();
		}

		private void FillViewStateVariables()
		{
			string pageSection = Request.QueryString["view"];
			if (Array.IndexOf(Enum.GetNames(typeof(EnumHelper.PageSection)), pageSection) > -1)
			{
				CurrentPageSection =
					(EnumHelper.PageSection)Enum.Parse(typeof(EnumHelper.PageSection), pageSection);
			}
		}

		private void FillEditForm()
		{
			string sUserId = Request.QueryString["id"];
			int iUserId;
			if (!String.IsNullOrEmpty(sUserId) && int.TryParse(sUserId, out iUserId))
			{
				SiteUserExtended siteUserExtended = SiteUserExtended.Get(iUserId);
				if (siteUserExtended != null)
				{
					CurrentSiteUserExtended = siteUserExtended;

					txtEmail.Text = siteUserExtended.BaseInfo.Email;
					txtFirstName.Text = siteUserExtended.FirstName;
					txtMiddleName.Text = siteUserExtended.MiddleName;
					txtLastName.Text = siteUserExtended.LastName;
				}
			}
		}

		private void FillPage()
		{
			switch (CurrentPageSection)
			{
				case EnumHelper.PageSection.Edit:
				case EnumHelper.PageSection.Add:
					mvUserManagement.ActiveViewIndex = 1;
					FillEditForm();
					FillRolesList();

					break;
				case EnumHelper.PageSection.Import:
					mvUserManagement.ActiveViewIndex = 2;

					break;
				default:
					mvUserManagement.ActiveViewIndex = 0;
					FillUserList(String.Empty);
					FillLetterList();

					break;
			}
		}

		private void FillUserList(string sFirstLetter)
		{
			List<SiteUserExtended> lSiteUser = SiteUserExtended.GetAllUsers();

			if (!String.IsNullOrEmpty(sFirstLetter))
			{
				lSiteUser = new List<SiteUserExtended>(lSiteUser.Where(i => i.LastName.StartsWith(sFirstLetter)));
			}

			rptSiteUser.DataSource = lSiteUser;
			rptSiteUser.DataBind();
		}

		private void FillRolesList()
		{
			List<AccessRole> lAccessRoles = AccessRole.GetAllRoles();
			if (lAccessRoles != null)
			{
				rptUserRoles.DataSource = lAccessRoles;
				rptUserRoles.DataBind();
			}
		}

		#endregion

		#region Other methods

		protected bool GetRoleState(object oRoleId)
		{
			if (oRoleId != null && oRoleId is Int32)
			{
				AccessRole role = AccessRole.Get(Convert.ToInt32(oRoleId));
				return CurrentSiteUserExtended.BaseInfo.AccessRoles.Contains(role);
			}
			return false;
		}

		protected string GetUserIconActivityToolTip(object oIsActivated)
		{
			if (oIsActivated is Boolean)
			{
				return Convert.ToBoolean(oIsActivated)
						? NgoResource.resUserSetInactive
						: NgoResource.resUserSetActive;
			}
			return String.Empty;
		}

		protected string GetUserIconLockStateToolTip(object oIsLockedOut)
		{
			if (oIsLockedOut is Boolean)
			{
				return Convert.ToBoolean(oIsLockedOut)
						? NgoResource.resUserSetUnlock
						: NgoResource.resUserSetLock;
			}
			return String.Empty;
		}

		protected string GetUserDetails(object oUserItem)
		{
			if (oUserItem.GetType() != typeof(SiteUserExtended))
				return string.Empty;

			SiteUserExtended currentUserInfo = (SiteUserExtended)oUserItem;

			const string sUserDetailsFormat = "<span class=\"adminTableRowDetailsRowTitle\">{0}:</span> <span class=\"adminTableRowDetailsRowValue\">{1}</span><br />";

			StringBuilder sbUserDetails = new StringBuilder();
			sbUserDetails.AppendFormat(sUserDetailsFormat, NgoResource.resFirstName, currentUserInfo.FirstName);
			sbUserDetails.AppendFormat(sUserDetailsFormat, NgoResource.resMiddleName, currentUserInfo.MiddleName);
			sbUserDetails.AppendFormat(sUserDetailsFormat, NgoResource.resLastName, currentUserInfo.LastName);
			sbUserDetails.Append("<br />");
			sbUserDetails.AppendFormat(sUserDetailsFormat, NgoResource.resJobPosition, currentUserInfo.JobPosition);
			if (currentUserInfo.JobId != null)
				sbUserDetails.AppendFormat(sUserDetailsFormat, NgoResource.resJob, Job.Get(currentUserInfo.JobId.Value).FullName);

			return sbUserDetails.ToString();
		}

		private IEnumerable<SiteUserExtended> ParseUserList(IEnumerable<string> userListFileContent)
		{
			List<SiteUserExtended> parsedUsers = new List<SiteUserExtended>();

			foreach (string sUserInfo in userListFileContent)
			{
				string[] sUserInfoParts = sUserInfo.Split('\t');

				if (sUserInfoParts.Length == 3)
				{
					SiteUserExtended siteUser = new SiteUserExtended();

					string sFioPart = sUserInfoParts.Length > 0 ? sUserInfoParts[0] : String.Empty;
					string sCityPart = sUserInfoParts.Length > 1 ? sUserInfoParts[1] : String.Empty;
					string sMailPart = sUserInfoParts.Length > 2 ? sUserInfoParts[2] : String.Empty;

					string[] sUserInfoFioParts = sFioPart.Split(' ');

					siteUser.LastName = sUserInfoFioParts.Length > 0 && !String.IsNullOrEmpty(sUserInfoFioParts[0]) ? sUserInfoFioParts[0] : String.Empty;
					siteUser.FirstName = sUserInfoFioParts.Length > 1 && !String.IsNullOrEmpty(sUserInfoFioParts[1]) ? sUserInfoFioParts[1] : String.Empty;
					siteUser.MiddleName = sUserInfoFioParts.Length > 2 && !String.IsNullOrEmpty(sUserInfoFioParts[2]) ? sUserInfoFioParts[2] : String.Empty;

					if (!RegexHelper.IsEmail(sMailPart))
						throw new Exception("Неверный формат Email пользователя");

					siteUser.BaseInfo.Email = sMailPart;

					if (!String.IsNullOrEmpty(sCityPart))
					{
						City userCity = City.SearchByName(sCityPart);
						if (userCity != null)
						{
							if (!userCity.CountryId.HasValue || !userCity.RegionId.HasValue)
								throw new Exception("Ошибка БД. Невозможно обнаружить привязку города");

							Country userCountry = Country.Get(userCity.CountryId.Value);
							Region userRegion = Region.Get(userCity.RegionId.Value);
							if (userCountry == null || userRegion == null)
								throw new Exception("Ошибка БД. Невозможно загрузить данные о стране или регионе");

							if (!userCountry.IsVisible.HasValue || !userCountry.IsVisible.Value)
							{
								userCountry.IsVisible = true;
								userCountry.Update();
							}

							if (!userRegion.IsVisible.HasValue || !userRegion.IsVisible.Value)
							{
								userRegion.IsVisible = true;
								userRegion.Update();
							}

							if (!userCity.IsVisible.HasValue || !userCity.IsVisible.Value)
							{
								userCity.IsVisible = true;
								userCity.Update();
							}
						}
					}
					parsedUsers.Add(siteUser);
				}
			}
			return parsedUsers;
		}

		private void SaveParsedUsers(IEnumerable<SiteUserExtended> parsedUsers)
		{
			List<SiteUserExtended> lSavedUsers = new List<SiteUserExtended>();

			string sUnconfirmedUserRole = EnumHelper.RequiredRoles.UnconfirmedUser.ToString();
			if (!MembershipHelper.RoleService.RoleExists(sUnconfirmedUserRole))
			{
				MembershipHelper.RoleService.CreateRole(sUnconfirmedUserRole, "Неподтверждённый пользователь");
			}

			foreach (SiteUserExtended user in parsedUsers)
			{
				string sPassword = MembershipHelper.MembershipService.GeneratePassword(8, 0);

				MembershipCreateStatus createStatus;
				MembershipUser newUser = MembershipHelper.MembershipService.CreateUser(user.BaseInfo.Email, sPassword, false, out createStatus);
				if (createStatus == MembershipCreateStatus.Success)
				{
					user.UserId = Convert.ToInt32(newUser.ProviderUserKey);
					user.Update();

					user.BaseInfo.Password = sPassword;

					lSavedUsers.Add(user);
				}
			}
			MembershipHelper.RoleService.AddUsersToRoles(lSavedUsers.Select(user => user.BaseInfo.Email).ToArray(),
			                                             new[] {sUnconfirmedUserRole});

			if (chkSendUserNotice.Checked)
			{
				EmailTemplate etWelcome = EmailTemplate.GetEmailTemlateByType((int)EnumHelper.EmailTemplateType.Welcome);
				if (etWelcome == null)
					return;

				foreach (SiteUserExtended savedUser in lSavedUsers)
				{
					MailHelper.SendEmail(etWelcome,
										 savedUser.BaseInfo.Email,
										 true,
										 new[]
					                     	{
					                     		savedUser.FirstName,
					                     		savedUser.MiddleName,
					                     		savedUser.BaseInfo.Email,
					                     		savedUser.BaseInfo.Password
					                     	});
				}
			}

			Response.Redirect(ListUrl);
		}

		private List<SiteUserExtended> GetSelectedUsers()
		{
			List<SiteUserExtended> lstSelectedUsers = (from RepeaterItem item in rptSiteUser.Items
													   let cbSelectUser = (CheckBox)item.FindControl("cbSelectUser")
													   let hlUserEmail = (HyperLink)item.FindControl("hlUserEmail")
													   where cbSelectUser != null && cbSelectUser.Checked && hlUserEmail != null
													   select SiteUserExtended.SearchByEmail(hlUserEmail.Text)).ToList();

			lstSelectedUsers.RemoveAll(siteUser => siteUser == null);

			return lstSelectedUsers;
		}

		private void SendProfileActionMail(SiteUserExtended siteUser, bool? bKeyValue, EnumHelper.EmailTemplateType etTrueTemplate, EnumHelper.EmailTemplateType etFalseTemplate)
		{
			if (!bKeyValue.HasValue)
				return;

			EmailTemplate etActivatedState =
				EmailTemplate.GetEmailTemlateByType(bKeyValue.Value ? (int)etTrueTemplate : (int)etFalseTemplate);

			MailHelper.SendEmail(etActivatedState,
								 siteUser.BaseInfo.Email,
								 true,
								 new[]
					                     	{
					                     		siteUser.FirstName,
					                     		siteUser.MiddleName
					                     	});
		}

		#endregion

		#region Event handlers

		protected void Page_Load(object sender, EventArgs e)
		{
			if (!Page.IsPostBack)
			{
				FillViewStateVariables();
				FillPage();
			}
		}

		protected void btnSaveUser_Click(object sender, EventArgs e)
		{
			List<AccessRole> selectedRoles = (from RepeaterItem item in rptUserRoles.Items
											  select (CheckBox)item.FindControl("cbRole")
												  into cbRole
												  where cbRole != null && cbRole.Checked
												  select AccessRole.SearchByName(cbRole.Text)
													  into role
													  where role != null
													  select role).ToList();

			AccessRole[] rolesForDelete =
				CurrentSiteUserExtended.BaseInfo.AccessRoles.Where(accessRole => !selectedRoles.Contains(accessRole)).ToArray();

			AccessRole[] rolesForAdd =
				selectedRoles.Where(selectedRole => !CurrentSiteUserExtended.BaseInfo.AccessRoles.Contains(selectedRole)).ToArray();

			MembershipHelper.RoleService.RemoveUsersFromRoles(new[] {CurrentSiteUserExtended.BaseInfo.Email},
			                                                  rolesForDelete.ToArray().Select(role => role.Name).ToArray());
			MembershipHelper.RoleService.AddUsersToRoles(new[] {CurrentSiteUserExtended.BaseInfo.Email},
			                                             rolesForAdd.ToArray().Select(role => role.Name).ToArray());

			CurrentSiteUserExtended.FirstName = txtFirstName.Text.Trim();
			CurrentSiteUserExtended.MiddleName = txtMiddleName.Text.Trim();
			CurrentSiteUserExtended.LastName = txtLastName.Text.Trim();
			CurrentSiteUserExtended.Update();

			CurrentSiteUserExtended.BaseInfo.Email = txtEmail.Text.Trim();
			CurrentSiteUserExtended.BaseInfo.UpdateInstance();

			Response.Redirect(ListUrl);
		}

		private void AddUserToSiteUsers(SiteUserExtended siteUser)
		{
			if (!siteUser.BaseInfo.IsActivated.HasValue)
				return;

			if (!siteUser.BaseInfo.IsActivated.Value)
			{
				string sUserRole = EnumHelper.RequiredRoles.User.ToString();
				string sUnconfirmedUserRole = EnumHelper.RequiredRoles.UnconfirmedUser.ToString();

				if (!MembershipHelper.RoleService.RoleExists(sUserRole))
				{
					MembershipHelper.RoleService.CreateRole(sUserRole, "Пользователь");
				}

				if (!MembershipHelper.RoleService.IsUserInRole(siteUser.BaseInfo.Email, sUserRole))
				{
					MembershipHelper.RoleService.AddUsersToRoles(new[] { siteUser.BaseInfo.Email },
																 new[] { sUserRole });
				}

				if (MembershipHelper.RoleService.IsUserInRole(siteUser.BaseInfo.Email, sUnconfirmedUserRole))
				{
					MembershipHelper.RoleService.RemoveUsersFromRoles(new[] { siteUser.BaseInfo.Email },
																	  new[] { sUnconfirmedUserRole });
				}
			}
		}

		protected void rptSiteUser_ItemCommand(object source, RepeaterCommandEventArgs e)
		{
			if (e.CommandName == "SetUserActivity" || e.CommandName == "SetUserLockState")
			{
				int iUserId = Convert.ToInt32(e.CommandArgument);
				if (iUserId == 0)
					return;

				SiteUserExtended siteUser = SiteUserExtended.Get(iUserId);
				if (siteUser == null)
					return;

				if (e.CommandName == "SetUserActivity")
				{
					AddUserToSiteUsers(siteUser);

					siteUser.BaseInfo.IsActivated = !siteUser.BaseInfo.IsActivated;
					siteUser.BaseInfo.UpdateInstance();

					SendProfileActionMail(siteUser,
										  siteUser.BaseInfo.IsActivated,
										  EnumHelper.EmailTemplateType.Activate,
										  EnumHelper.EmailTemplateType.Deactivate);
				}
				else if (e.CommandName == "SetUserLockState")
				{
					if (!siteUser.BaseInfo.IsLockedOut.HasValue)
						return;

					if (!siteUser.BaseInfo.IsLockedOut.Value)
					{
						siteUser.BaseInfo.IsLockedOut = true;
						siteUser.BaseInfo.LastLockedOutDate = DateTime.Now;
						siteUser.BaseInfo.LastLockedOutReason = NgoResource.resLockYourAccountReason;
					}
					else
					{
						siteUser.BaseInfo.IsLockedOut = false;
					}

					siteUser.BaseInfo.UpdateInstance();

					SendProfileActionMail(siteUser,
										  siteUser.BaseInfo.IsLockedOut,
										  EnumHelper.EmailTemplateType.Lock,
										  EnumHelper.EmailTemplateType.Unlock);

				}
				Response.Redirect(ListUrl);
			}
			else if (e.CommandName == "SendInvitations")
			{
				List<SiteUserExtended> lstSelectedUsers = GetSelectedUsers();
				if (lstSelectedUsers == null || lstSelectedUsers.Count == 0)
					return;

				EmailTemplate etInvitation = EmailTemplate.GetEmailTemlateByType((int)EnumHelper.EmailTemplateType.Invitation);
				if (etInvitation == null)
					return;

				for (int userIndex = 0; userIndex < lstSelectedUsers.Count; userIndex++)
				{
					SiteUserExtended selectedUser = lstSelectedUsers[userIndex];
					if (!selectedUser.UserId.HasValue)
						return;
					
					string sNewPassword = MembershipHelper.MembershipService.ResetPassword(selectedUser.BaseInfo.Email);
					if (String.IsNullOrEmpty(sNewPassword))
						return;

					AddUserToSiteUsers(selectedUser);

					selectedUser = SiteUserExtended.Get(selectedUser.UserId.Value);

					selectedUser.BaseInfo.IsActivated = true;
					selectedUser.BaseInfo.UpdateInstance();

					MailHelper.SendEmail(etInvitation,
					                     selectedUser.BaseInfo.Email,
					                     true,
					                     new[]
					                     	{
					                     		selectedUser.FirstName,
					                     		selectedUser.MiddleName,
					                     		selectedUser.BaseInfo.Email,
					                     		sNewPassword
					                     	});
				}
			}
			else if (e.CommandName == "SendFreeEmail")
			{
				List<SiteUserExtended> lstSelectedUsers = GetSelectedUsers();
				if (lstSelectedUsers == null || lstSelectedUsers.Count == 0)
					return;

				SessionHelper.UserList = lstSelectedUsers;
				Response.Redirect("/admin/SendEmail.aspx");
			}
			else if (e.CommandName == "DeleteUser")
			{
				MembershipHelper.MembershipService.DeleteUser(e.CommandArgument.ToString());
				Response.Redirect(ListUrl);
			}
		}

		protected void btnList_Click(object sender, EventArgs e)
		{
			Response.Redirect(ListUrl);
		}

		protected void btnImportUsers_Click(object sender, EventArgs e)
		{
			List<string> userListFileContent = new List<string>();

			using (StreamReader streamReader = new StreamReader(fuSiteUser.PostedFile.InputStream, Encoding.GetEncoding("windows-1251")))
			{
				while (!streamReader.EndOfStream)
				{
					userListFileContent.Add(streamReader.ReadLine());
				}
			}

			SaveParsedUsers(new List<SiteUserExtended>(ParseUserList(userListFileContent)));
		}

		protected void rptAlphabetLinks_ItemCommand(object source, RepeaterCommandEventArgs e)
		{
			if (e.CommandName == "FilterByName")
			{
				string sFirstLetter = e.CommandArgument.ToString();

				if (e.CommandArgument.ToString() == "Список")
					sFirstLetter = String.Empty;
				FillUserList(sFirstLetter);
			}
		}

		#endregion
	}
}